package com.hjx.leetcode;

import java.util.HashMap;
import java.util.Map;

/**
 * 8. 字符串转换整数 (atoi)
 *
 * 请你来实现一个 atoi 函数，使其能将字符串转换成整数。
 *
 * 首先，该函数会根据需要丢弃无用的开头空格字符，直到寻找到第一个非空格的字符为止。
 *
 * 当我们寻找到的第一个非空字符为正或者负号时，则将该符号与之后面尽可能多的连续数字组合起来，作为该整数的正负号；
 * 假如第一个非空字符是数字，则直接将其与之后连续的数字字符组合起来，形成整数。
 *
 * 该字符串除了有效的整数部分之后也可能会存在多余的字符，这些字符可以被忽略，它们对于函数不应该造成影响。
 *
 * 注意：假如该字符串中的第一个非空格字符不是一个有效整数字符、字符串为空或字符串仅包含空白字符时，则你的函数不需要进行转换。
 *
 * 在任何情况下，若函数不能进行有效的转换时，请返回 0。
 *
 * 说明：
 *
 * 假设我们的环境只能存储 32 位大小的有符号整数，那么其数值范围为 [−2^31,  2^31 − 1]。
 * 如果数值超过这个范围，请返回  INT_MAX (2^31 − 1) 或 INT_MIN (−2^31) 。
 *
 * 示例 1:
 *
 * 输入: "42"
 * 输出: 42
 *
 * 示例 2:
 *
 * 输入: "   -42"
 * 输出: -42
 * 解释: 第一个非空白字符为 '-', 它是一个负号。
 *      我们尽可能将负号与后面所有连续出现的数字组合起来，最后得到 -42 。
 *
 * 示例 3:
 *
 * 输入: "4193 with words"
 * 输出: 4193
 * 解释: 转换截止于数字 '3' ，因为它的下一个字符不为数字。
 *
 * 示例 4:
 *
 * 输入: "words and 987"
 * 输出: 0
 * 解释: 第一个非空字符是 'w', 但它不是数字或正、负号。
 *      因此无法执行有效的转换。
 *
 * 示例 5:
 *
 * 输入: "-91283472332"
 * 输出: -2147483648
 * 解释: 数字 "-91283472332" 超过 32 位有符号整数范围。
 *      因此返回 INT_MIN (−2^31) 。
 *
 * 来源：力扣（LeetCode）
 * 链接：https://leetcode-cn.com/problems/string-to-integer-atoi
 * 著作权归领扣网络所有。商业转载请联系官方授权，非商业转载请注明出处。
 */
class LeetCode_8 {

    /**
     * 此题解用到了64位环境变量，面试官如果未要求环境变量，这种题解是一种不错的解法，可以借鉴来看一下。
     * 1.首先去除字符串左右空格,不符合条件的直接return 0;
     * 2.sign是符号位,start指针指向第一个数字的位置,如果第一位为数字,则sign=1,start=0,否则firstChar接收字符串第一个字符,若为“+”、“-”,sign分别赋值1、-1,start自增1,
     * 3.从字符串第一个为数字的位置开始遍历,res为无符号结果,如果res大于Integer最大值且sign=1,输出Integer的最大值,反之输出Integer最小值,如果遍历到不为数字的字符,则直接返回res*sign;
     * 4.如果遍历时该字符串未超范围,且无非数字字符,则返回res * sign;
     * 5.完结。
     *
     * 作者：spirit-9
     * 链接：https://leetcode-cn.com/problems/string-to-integer-atoi/solution/java-yi-dong-yi-jie-xiao-lu-gao-by-spirit-9-27/
     * 来源：力扣（LeetCode）
     * 著作权归作者所有。商业转载请联系作者获得授权，非商业转载请注明出处。
     *
     * @param str
     * @return
     */
    public int myAtoi(String str) {
        if (str == null) {
            return 0;
        }
        str = str.trim();
        if (str.length() == 0) {
            return 0;
        }

        char firstChar = str.charAt(0);
        int sign = 1;
        int start = 0;
        long res = 0;
        if (firstChar == '+') {
            sign = 1;
            start++;
        } else if (firstChar == '-') {
            sign = -1;
            start++;
        }

        for (int i = start; i < str.length(); i++) {
            //遇到非数字停止遍历
            if (!Character.isDigit(str.charAt(i))) {
                return (int) res * sign;
            }
            res = res * 10 + str.charAt(i) - '0';
            //越界取上下界值
            if (sign == 1 && res > Integer.MAX_VALUE)
                return Integer.MAX_VALUE;
            if (sign == -1 && res > Integer.MAX_VALUE)
                return Integer.MIN_VALUE;
        }
        return (int) res * sign;
    }

    public int myAtoi1(String str) {
        if ("".equals(str)){
            return 0;
        }
        Map<Character, String> map = new HashMap<>();
        map.put('+', "operator");
        map.put(' ', "skip");
        map.put('0', "digit");
        map.put('1', "digit");
        map.put('2', "digit");
        map.put('3', "digit");
        map.put('4', "digit");
        map.put('5', "digit");
        map.put('6', "digit");
        map.put('7', "digit");
        map.put('8', "digit");
        map.put('9', "digit");
        map.put('-', "operator");
        char[] chars = str.toCharArray();
        int begin = 0;
        int end = 0;
        boolean beginFlag = false;
        boolean allIsEmpty = true;
        for (int i = 0; i < chars.length; i++) {
            //第一个非空字符不在映射中，直接返回0
            if (map.get(chars[i]) == null){
                break;
            }
            //在映射中标记起始索引
            if("operator".equals(map.get(chars[i])) || "digit".equals(map.get(chars[i]))) {
                //第一次执行
                if (!beginFlag){
                    if (chars[i] != '0'){
                        beginFlag = true;
                    }

                    begin = i;
                    end = i;
                } else {
                    if ("operator".equals(map.get(chars[i]))){
                        return 0;
                    }

                    end = i;
                }
            } else if("skip".equals(map.get(chars[i])) || map.get(chars[i]) == null){
                if (beginFlag){
                    break;
                }

            }

            allIsEmpty = allIsEmpty && (chars[i] == ' ');

        }


        if (allIsEmpty){
            return 0;
        }
        if (begin == end){
            if("digit".equals(map.get(chars[begin]))){
                return Integer.valueOf(str.substring(begin, end+1));
            } else {
                return 0;
            }
        }
        //long 型范围  - 2^63 ~ 2^63 - 1
        if (end - begin + 1 >= 19){
            if(chars[begin] == '-'){
                return Integer.MIN_VALUE;
            } else {
                return Integer.MAX_VALUE;
            }
        }

        long res = Long.valueOf(str.substring(begin, end+1));
        if (res >= Integer.MAX_VALUE){
            return Integer.MAX_VALUE;
        }
        if(res <= Integer.MIN_VALUE){
            return Integer.MIN_VALUE;
        }

        return (int) res;
    }
}
